/**
 * Copyright (c) 2011, www.quartzsource.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.quartzsource.core

case class NodeId(id: Binary) extends Ordered[NodeId] {
  require(id != null)
  require(id.size == 20)

  override def toString() = {
    id.map("%02x".format(_)).foldLeft("") { _ + _ }
  }

  def hex: String = {
    NodeId.hexlify(id)
  }

  def short: String = {
    NodeId.hexlify(id.take(6))
  }

  override def compare(that: NodeId): Int = {
    hex compareTo that.hex
  }
}

/**
 * basic nodeid manipulation for Quartz
 */
object NodeId {
  val NULLREV = -1
  val NULLID = NodeId(scala.collection.mutable.ArraySeq.fill(20)(0.toByte)) //initiated with 0's

  private val HEX_DIGIT = "0123456789abcdef".toCharArray()

  def hexlify(bin: Binary): String = {
    //http://forums.xkcd.com/viewtopic.php?f=11&t=16666&p=553936
    val buf = new StringBuilder(bin.size << 1) // bin.size * 2
    bin.foreach(ch => {
      buf.append(NodeId.HEX_DIGIT((ch >>> 4) & 0xF))
      buf.append(NodeId.HEX_DIGIT(ch & 0xF))
    })
    buf.toString
  }

  def unhexlify(nodeId: String): NodeId = {
    require(nodeId != null)
    require(nodeId.size == 40)
    val buf = new scala.collection.mutable.ArrayBuffer[Byte](20)
    for (i <- 0 until 40 by 2) {
      val top = Character.digit(nodeId.charAt(i), 16)
      require(top != -1)
      val bottom = Character.digit(nodeId.charAt(i + 1), 16)
      require(bottom != -1)
      buf.append(((top << 4) | bottom).toByte)
    }
    NodeId(Binary(buf.toArray))
  }

  //very convenient for tests
  def apply(str: String): NodeId = {
    unhexlify(str)
  }
}
